package com.lhz.framework.security.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lhz.framework.config.converter.TimeStampToLocalDateConverter;
import com.lhz.framework.converter.TimeStampToDateConverter;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.util.ArrayList;
import java.util.List;

/**
 * @author lihuazhi
 */
@Configuration
public class WebMvcRegistrationsConfig extends WebMvcConfigurationSupport {

    /**
     * 文件存储的根路径
     */
    @Value("${sys.file.root-path}")
    private String fileRootPath;

    @Resource
    private AuthenticationHandlerInterceptor authenticationHandlerInterceptor;

    @Resource
    private RateLimiterHandlerInterceptor rateLimiterHandlerInterceptor;

    @Resource
    private ObjectMapper serializingObjectMapper;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        // 无需拦截的接口集合
        List<String> ignorePath = new ArrayList<>();
        // swagger
        ignorePath.add("/swagger-resources/**");
        ignorePath.add("/doc.html");
        ignorePath.add("/swagger-ui.html");
        ignorePath.add("/v2/**");
        ignorePath.add("/v3/**");
        ignorePath.add("/webjars/**");

        ignorePath.add("/static/**");
        ignorePath.add("/templates/**");
        ignorePath.add("/error");

        // 文件静态资源访问
        ignorePath.add("/source/**");
        ignorePath.add("/view/**");
        ignorePath.add("/download/**");

        //先拦截认证
        registry.addInterceptor(authenticationHandlerInterceptor).addPathPatterns("/**").excludePathPatterns(ignorePath);

        //所有请求都会被拦截 进行限流处理
        registry.addInterceptor(rateLimiterHandlerInterceptor).addPathPatterns("/**").excludePathPatterns(ignorePath);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");
        // swagger2资源
        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");

        // 文件静态资源虚拟路径
        registry.addResourceHandler("/source/**").addResourceLocations("file:" + fileRootPath + "/source/");
        registry.addResourceHandler("/view/**").addResourceLocations("file:" + fileRootPath + "/view/");
        registry.addResourceHandler("/download/**").addResourceLocations("file:" + fileRootPath + "/download/");
    }

    /**
     * 添加自定义消息转换器
     */
    @Override
    protected void addFormatters(FormatterRegistry registry) {
        // 添加时间戳转日期类型消息转换器
        registry.addConverter(new TimeStampToDateConverter());
        // 添加时间戳转日期类型消息转换器
        registry.addConverter(new TimeStampToLocalDateConverter());
    }

    /**
     * 重新配置返回格式，（引入xml包后，会返回xml格式数据）
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.APPLICATION_JSON);
    }

    /**
     * 添加自定义消息转换器
     */
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setObjectMapper(serializingObjectMapper);
        converters.add(converters.size() - 1, converter);
    }
}